﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Text.RegularExpressions;
using System.IO;

namespace com.qbengo.utility.nodepicker
{
    public partial class NodePick : Form
    {
        private string pictureName;//图片的路径
        private Bitmap curBitmap; //图片的位图图像
        private Point pictureOrigin = new Point(200, 20);//图片原点，图片的左上角
        private const int pictureLength = 1024; //图片的长
        private const int pictureWidth = 1024;  //图片的宽
        private List<NodeGraphic> nodeList = new List<NodeGraphic>(); //存储选择的点的list
        private List<NodeDistance> distanceList = new List<NodeDistance>();//存储距离的list 
        private int nodeStartId = 0;    //node开始的id号
        private NodeGraphic curANode, curBNode;//当前添加到distanceList的的点
        private bool respond = true;
        private int xOffset;
        private int yOffset;

        private int mapID = 0;   //map的ID
        public NodePick(int mapID=0)
        {
            InitializeComponent();
            //nodeStartIDTextBox.Text = nodeStartId.ToString();
            this.mapID = mapID;
            
        }
        /// <summary>
        /// 由用户找到图片的路径
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void selectPictureButton_Click(object sender, EventArgs e)
        {
            //创建OpenFileDialg
            OpenFileDialog opnDlg = new OpenFileDialog();

            //为图像选择一个筛选器
            opnDlg.Filter = "all picture file|*.bmp;*.pcx;*.png;*.jpg;*.gif;" +
                "*.tif;*.ico;*.dxf;*.cgm;*.cdr;*.wmf;*.eps;*.emf|" +
                "bitmap(*.bmp;*.jpg;*.png;...)|*.bmp;*.pcx;*.png;*.jpg;*.gif;*.tif;*.ico|" +
                "vectogram(*.wmf;*.eps;*.emf;...)|*.dxf;*.cgm;*.cdr;*.wmf;*.eps;*.emf";
            //设置对话框标题
            opnDlg.Title = "打开图像文件";
            //启用”帮助“按钮
            opnDlg.ShowHelp = true;

            //如果结果为“打开”，选定文件
            if (opnDlg.ShowDialog() == DialogResult.OK)
            {
                //读取当前选中的文件名
                pictureName = opnDlg.FileName;
                //使用Image.FromFile创建图像对象
                try
                {
                    curBitmap = (Bitmap)Image.FromFile(pictureName);
                }
                catch (Exception exp)
                {
                    //抛出异常
                    MessageBox.Show(exp.Message);
                }

                nodeList.Clear();//移除所有点
                distanceList.Clear();//移除所有距离
                curANode = null;
                curBNode = null;
                AtextBox.Text = String.Empty;
                BtextBox.Text = String.Empty;

                nodeDataGridView.Rows.Clear();
                distanceDataGridView.Rows.Clear();


                Invalidate();
            }
        }
        /// <summary>
        /// 绘制图片
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            //获取Graphics对象
            Graphics g = e.Graphics;

            if (curBitmap != null)
            {
                //使用DrawImage 方法绘制图像
                //160,20：显示在主窗体内，图像左上角的坐标
                //curBitmap.Width,curBitmap.Height:图像的宽度和高度
                g.TranslateTransform(this.AutoScrollPosition.X, this.AutoScrollPosition.Y); //应用平移变换
                g.DrawImage(curBitmap, pictureOrigin.X, pictureOrigin.Y, pictureWidth, pictureLength);
            }

            Pen redPen = new Pen(Brushes.Red, 2); //宽度为1的红色画笔
            foreach (NodeGraphic node in nodeList)
            {
                Point point = NormalCoordinateToWorld(node);
                g.DrawEllipse(redPen, point.X - 3, point.Y - 3, 6, 6);//画出边长为6的正方形所包围的圆。

                g.DrawString(node.ID.ToString(),
                new Font("Bold", 10), Brushes.Chocolate, new PointF(point.X, point.Y - 15));
            }
            Pen blackPen = new Pen(Brushes.Black, 2); //宽度为2的黑色画笔
            foreach (NodeDistance nodeDistance in distanceList)    //画出distanceList中的距离的线
            {
                g.DrawLine(blackPen, NormalCoordinateToWorld(nodeDistance.ANode),
                    NormalCoordinateToWorld(nodeDistance.BNode));
            }
            if (curANode != null && curBNode != null)
            {
                g.DrawLine(blackPen, NormalCoordinateToWorld(curANode),   //画出现在的A、B节点的直线
                    NormalCoordinateToWorld(curBNode));
            }
        }
        /// <summary>
        /// 鼠标按下在图片上选点，将选择的点保存在pointList和pointCheckedListBox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            if (curBitmap == null)
                return;

            NodeGraphic node;
            xOffset = this.AutoScrollPosition.X;
            yOffset = this.AutoScrollPosition.Y;
            int x = e.X - xOffset;   //全局坐标
            int y = e.Y - yOffset;   //全局坐标

            if (x >= pictureOrigin.X && x <= pictureOrigin.X + pictureWidth &&
            y >= pictureOrigin.Y && y <= pictureOrigin.Y + pictureLength)
            {
                node = new NodeGraphic(mapID * 100000 + nodeStartId + nodeList.Count,
                    WorldCoordinateNormalise(x, y));

                //Pen curPen = new Pen(Brushes.Red, 2); //宽度为1的黑色画笔
                Pen curPen = new Pen(Brushes.Chocolate, 2); //宽度为1的黑色画笔
                Graphics g = this.CreateGraphics();

                g.TranslateTransform(this.AutoScrollPosition.X, this.AutoScrollPosition.Y); //应用平移变换
                g.DrawEllipse(curPen, x - 3, y - 3, 6, 6);//画出边长为6的正方形所包围的圆。

                g.DrawString((mapID * 100000 + nodeStartId + nodeList.Count).ToString(),
                    new Font("Bold", 10), Brushes.Black,
                    new PointF(x, y - 15));

                nodeList.Add(node);

                nodeDataGridView.Rows.Add();  //增加一行

                respond = false;
                nodeDataGridView[0, nodeList.Count - 1].Value = node.ID;
                nodeDataGridView[1, nodeList.Count - 1].Value = node.X;
                nodeDataGridView[2, nodeList.Count - 1].Value = node.Y;
                respond = true;
            }
        }
        /// <summary>
        /// 退出
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void closeButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        /// <summary>
        /// 将nodeDataGridView处于活动的的单元格所在的行的node作为A节点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void addToAButton_Click(object sender, EventArgs e)
        {
            if (nodeDataGridView.CurrentCell == null)                    //没有处于活动的单元格                
            {
                MessageBox.Show("Please first select a cell !");//MessageBox.Show("请先选择数据所在的一个单元格！");
                return;
            }

            curANode = nodeList[nodeDataGridView.CurrentCell.RowIndex];
            AtextBox.Text = curANode.ID.ToString();

        }


        /// <summary>
        /// 将nodeDataGridView处于活动的的单元格所在的行的node作为B节点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void addToBButton_Click(object sender, EventArgs e)
        {
            if (nodeDataGridView.CurrentCell == null)                 //没有处于活动的单元格
            {
                MessageBox.Show("Please first select a cell !");//MessageBox.Show("请先选择数据所在的一个单元格！");
                return;
            }
            curBNode = nodeList[nodeDataGridView.CurrentCell.RowIndex];
            BtextBox.Text = curBNode.ID.ToString();
        }
        /// <summary>
        /// 计算A、B间的距离并用直线连接A、B
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void calculateShowButton_Click(object sender, EventArgs e)
        {
            if (curANode == null)
            {
                MessageBox.Show("Please first select Noda A!");//MessageBox.Show("请先选择A 节点！");
                return;
            }
            if (curBNode == null)
            {
                MessageBox.Show("Please first select Noda B!");
                return;
            }

            NodeDistance nodeDistance = new NodeDistance(distanceList.Count, curANode, curBNode);
            distanceTextBox.Text = nodeDistance.Distance.ToString();//显示距离


            Graphics g = this.CreateGraphics();
            g.TranslateTransform(this.AutoScrollPosition.X, this.AutoScrollPosition.Y); //应用平移变换

            Pen curPen = new Pen(Brushes.Black, 2); //宽度为1的黑色画笔

            g.DrawLine(curPen, NormalCoordinateToWorld(curANode),
                NormalCoordinateToWorld(curBNode));

        }
        /// <summary>
        /// addToList按钮所执行的操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void addToListButton_Click(object sender, EventArgs e)
        {
            if (curANode == null)
            {
                MessageBox.Show("Please first select Noda A !");
                return;
            }
            if (curBNode == null)
            {
                MessageBox.Show("Please first select Noda B !");
                return;
            }
            NodeDistance nodeDistance = new NodeDistance(distanceList.Count+mapID*100000, curANode, curBNode);

            foreach (NodeDistance test in distanceList)
            {
                if (test.ANode == nodeDistance.ANode && test.BNode == nodeDistance.BNode
                    || test.ANode == nodeDistance.BNode && test.BNode == nodeDistance.ANode)
                {
                    MessageBox.Show("The distance of A-B already exists!");//MessageBox.Show("添加的距离数据已经存在！");
                    return;
                }
            }
            distanceList.Add(nodeDistance);

            distanceDataGridView.Rows.Add(); //增加一行
            distanceDataGridView[0, distanceList.Count - 1].Value = distanceList[distanceList.Count - 1].ID;//distID
            distanceDataGridView[1, distanceList.Count - 1].Value = distanceList[distanceList.Count - 1].ANodeID;//A的ID
            distanceDataGridView[2, distanceList.Count - 1].Value = distanceList[distanceList.Count - 1].BNodeID;//B的ID
            distanceDataGridView[3, distanceList.Count - 1].Value = distanceList[distanceList.Count - 1].Distance;//距离           
        }
        /// <summary>
        /// 删除一个节点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void delateNodeButton_Click(object sender, EventArgs e)
        {
            int row;
            DialogResult dialogResult;//设置对话框的返回值

            if (nodeDataGridView.CurrentCell == null)
            {
                MessageBox.Show("Please first select the node!");
                return;
            }
            dialogResult = MessageBox.Show("delete the node?",
                "tip",//对话框的标题 
                MessageBoxButtons.YesNo);//对话框的显示内容 
            if (dialogResult == DialogResult.Yes)
            {
                row = nodeDataGridView.CurrentCell.RowIndex;//删除的行号

                if (curANode == nodeList[row])
                {
                    curANode = null;
                    AtextBox.Text = String.Empty;
                }
                if (curBNode == nodeList[row])
                {
                    curBNode = null;
                    BtextBox.Text = String.Empty;
                }

                for (int i = 0; i < distanceList.Count; i++)         //在distanceList中删除此节点
                {
                    if (distanceList[i].ANode == nodeList[row] || distanceList[i].BNode == nodeList[row])
                    {
                        distanceDataGridView.Rows.RemoveAt(i);
                        distanceList.RemoveAt(i);
                        for (int j = 0; j < distanceList.Count; j++)
                        {
                            distanceList[j].ID = j;//重新编排ID
                            distanceDataGridView[0, j].Value = j;
                        }
                        i--;
                    }
                }


                nodeList.RemoveAt(row);                     //在nodelist中删除
                nodeDataGridView.Rows.RemoveAt(row);        //在nodeDataGridView中删除
                Invalidate();   //重绘
            }
        }
        /// <summary>
        /// 删除一个距离行时所触发的事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void delateDistanceButton_Click(object sender, EventArgs e)
        {
            int row;
            DialogResult dialogResult;//设置对话框的返回值
            if (nodeDataGridView.CurrentCell == null)
            {
                MessageBox.Show("Please first select the distance of A-B!");
                return;
            }
            dialogResult = MessageBox.Show("delete the distance of A-B？",
                "tip",//对话框的标题 
                MessageBoxButtons.YesNo);//对话框的显示内容 
            if (dialogResult == DialogResult.Yes)
            {
                row = distanceDataGridView.CurrentCell.RowIndex;
                distanceList.RemoveAt(row);                     //在distanceList中删除
                distanceDataGridView.Rows.RemoveAt(row);        //在distanceDataGridView中删除

                for (int i = 0; i < distanceList.Count; i++)
                {
                    distanceList[i].ID = i;//重新编排ID
                    distanceDataGridView[0, i].Value = i;
                }

                Invalidate();
            }

        }
        /// <summary>
        /// 单元格值改变时所触发的事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void nodeDataGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            int oldID, newID;
            if (e.ColumnIndex == 0 && e.RowIndex > -1   //改变的列为0且行为非负数。避免加载时触发事件
                && respond)                              //程序写入数据时不响应
            {
                oldID = nodeList[e.RowIndex].ID;   //获得更新前的ID
                if (!Regex.IsMatch(nodeDataGridView[e.ColumnIndex, e.RowIndex].Value.ToString()
                    , @"^\d+$"))
                {
                    MessageBox.Show("Please input nonnegative integer!");
                    nodeDataGridView[e.ColumnIndex, e.RowIndex].Value = oldID;
                    return;
                }
                newID = Convert.ToInt32(nodeDataGridView[e.ColumnIndex, e.RowIndex].Value); //更新后的ID

                nodeList[e.RowIndex].ID = newID;
                foreach (NodeDistance nodeDistance in distanceList)  //更新distanceDataGridView中的节点ID
                {
                    if (nodeDistance.ANode == nodeList[e.RowIndex])
                    {
                        distanceDataGridView[1, nodeDistance.ID].Value = newID;
                    }
                    if (nodeDistance.BNode == nodeList[e.RowIndex])
                    {
                        distanceDataGridView[2, nodeDistance.ID].Value = newID;
                    }
                }
                if (nodeList[e.RowIndex] == curANode)            //更新A节点
                {
                    AtextBox.Text = curANode.ID.ToString();
                }
                if (nodeList[e.RowIndex] == curBNode)         //更新B节点
                {
                    BtextBox.Text = curBNode.ID.ToString();
                }

                Invalidate();
            }

        }
        /// <summary>
        /// nodeStartIDTextBox 的值改变时所触发的事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void nodeStartIDTextBox_TextChanged(object sender, EventArgs e)
        {
            int id;
            if (nodeStartIDTextBox.Text == "")
                return;
            if (!Regex.IsMatch(nodeStartIDTextBox.Text, @"^\d+$"))  //判断输入的值为非负数
            {
                MessageBox.Show("Please input nonnegative integer!");
                nodeStartIDTextBox.Text = nodeStartId.ToString();
                return;
            }
            else
            {
                int old_id = nodeStartId;
                nodeStartId = Convert.ToInt32(nodeStartIDTextBox.Text);
                id = nodeStartId;


                respond = false;
                for (int i = 0; i < nodeList.Count; i++)
                {
                    nodeList[i].ID = nodeList[i].ID - old_id + id;
                    nodeDataGridView[0, i].Value = nodeList[i].ID;    //修改nodeDataGridView中的id值
                }
                respond = true;

                if (curANode != null)
                    AtextBox.Text = curANode.ID.ToString();
                if (curBNode != null)
                    BtextBox.Text = curBNode.ID.ToString();

                foreach (NodeDistance nodeDistance in distanceList)//修改distanceList和distanceDataGridView中的id值
                {
                    foreach (NodeGraphic node in nodeList)
                    {
                        if (nodeDistance.ANode == node)
                        {

                            distanceDataGridView[1, nodeDistance.ID].Value = node.ID;
                        }
                        if (nodeDistance.BNode == node)
                        {

                            distanceDataGridView[2, nodeDistance.ID].Value = node.ID;
                        }

                    }
                }
            }
            Invalidate();
            //PaintAllNodes();
        }

        /// <summary>
        /// 画出所有选择的点并且在图中标记
        /// </summary>
        private void PaintAllNodes()
        {
            Pen curPen = new Pen(Brushes.Red, 1); //宽度为1的红色画笔
            Graphics g = this.CreateGraphics();
            int pixelNum;
            foreach (NodeGraphic node in nodeList)
            {
                pixelNum = (node.ID.ToString().Length / 2) * 3;

                Point point = NormalCoordinateToWorld(node);
                g.DrawEllipse(curPen, point.X - 2, point.Y - 2, 4, 4);//画出边长为4的正方形所包围的圆。

                g.DrawString(node.ID.ToString(),
                new Font("New Timer", 8), Brushes.Black, new PointF(point.X - pixelNum, point.Y - 13));
            }
        }

        /// <summary>
        /// 将世界坐标转换为单位坐标
        /// </summary>
        /// <param name="x">X坐标</param>
        /// <param name="y">Y坐标</param>
        /// <returns></returns>
        private PointF WorldCoordinateNormalise(int x, int y)
        {
            PointF point;
            point = new PointF((float)(x - pictureOrigin.X) / pictureWidth, //point=new PointF((float)(x-pictureOrigin.X+1) / pictureWidth,     
            (float)(y - pictureOrigin.Y) / pictureLength);//    (float)(y-pictureOrigin.Y+1) / pictureLength);

            return point;
        }

        /// <summary>
        /// 将单位坐标转换为世界坐标
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private Point NormalCoordinateToWorld(NodeGraphic node)
        {
            Point point;
            point = new Point((int)(node.X * pictureWidth) + pictureOrigin.X,
            (int)(node.Y * pictureLength) + pictureOrigin.Y);

            return point;
        }
        /// <summary>
        /// 滑动滚动条时，重绘
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Scroll(object sender, ScrollEventArgs e)
        {
            //Invalidate();
        }
        /// <summary>
        /// 数据导出到文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void exportButton_Click(object sender, EventArgs e)
        {
            String exportFileName;

            SaveFileDialog saveFileDialog = new SaveFileDialog();

            saveFileDialog.Filter = "text file|*.txt;*doc";

            saveFileDialog.RestoreDirectory = true; //记忆上次打开的目录

            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                exportFileName = saveFileDialog.FileName.ToString(); //获得文件路径
                StreamWriter streamWriter = new StreamWriter(exportFileName);

                streamWriter.WriteLine(pictureName);       //图片的本地路径
                streamWriter.WriteLine(mapID);             //map_id
                streamWriter.WriteLine(nodeStartId);       //nodeStartId
                streamWriter.WriteLine(nodeList.Count);    //node的总数
                streamWriter.WriteLine(distanceList.Count);                  //distance的总数

                foreach (NodeGraphic node in nodeList)    //node的信息
                {
                    streamWriter.WriteLine(node.ID + "\t" + node.X + "\t" + node.Y);
                }

                foreach (NodeDistance nodeDistance in distanceList)  //nodeDistance 的信息
                {
                    streamWriter.WriteLine(nodeDistance.ID + "\t" + nodeDistance.ANodeID + "\t" + nodeDistance.BNodeID + "\t" + nodeDistance.Distance);
                }

                streamWriter.Flush();
                streamWriter.Close();

            }
        }

        /// <summary>
        /// 当nodeStartIDTextBox不再是活动控件时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void nodeStartIDTextBox_Leave(object sender, EventArgs e)
        {
            if (nodeStartIDTextBox.Text == "")
                nodeStartIDTextBox.Text = nodeStartId.ToString();
        }
      

        /// <summary>
        /// 选择导入存储图片数据的文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void importButton_Click(object sender, EventArgs e)
        {
            String exportFileName;     //导入文件的文件名
            String temp;
            String[] nodeInfo;
            String[] distanceInfo;
            int nodeNum = 0;
            int distanceNum = 0;


            NodeGraphic aNode = null;
            NodeGraphic bNode = null;

            //创建OpenFileDialg
            OpenFileDialog opnDlg = new OpenFileDialog();

            //为图像选择一个筛选器
            opnDlg.Filter = "text file|*.txt;*doc";
            //设置对话框标题
            opnDlg.Title = "打开图像数据文件";
            //启用”帮助“按钮
            opnDlg.ShowHelp = true;


            //如果结果为“打开”，选定文件
            if (opnDlg.ShowDialog() == DialogResult.OK)
            {
                exportFileName = opnDlg.FileName;

                StreamReader streamRead = new StreamReader(exportFileName);

                pictureName = streamRead.ReadLine();
                curBitmap = (Bitmap)Image.FromFile(pictureName);

                mapID = Convert.ToInt32(streamRead.ReadLine());
                nodeStartId = Convert.ToInt32(streamRead.ReadLine());

                nodeNum = Convert.ToInt32(streamRead.ReadLine());            //节点的总数
                distanceNum = Convert.ToInt32(streamRead.ReadLine());        //距离节点的总数

                
                nodeStartIDTextBox.Text = nodeStartId.ToString();    //更新nodeStartId

                for (int i = 0; i < nodeNum; i++)                          //读入节点
                {
                    temp = streamRead.ReadLine();
                    nodeInfo = temp.Split('\t');
                    NodeGraphic node = new NodeGraphic(Convert.ToInt32(nodeInfo[0]),
                        Convert.ToSingle(nodeInfo[1]), Convert.ToSingle(nodeInfo[2]));
                    nodeList.Add(node);
                }


                for (int i = 0; i < distanceNum; i++)                            //读入距离节点
                {
                    temp = streamRead.ReadLine();
                    distanceInfo = temp.Split('\t');
                    for (int j = 0; j < nodeList.Count; j++)
                    {
                        if (nodeList[j].ID.ToString() == distanceInfo[1])
                            aNode = nodeList[j];
                        if (nodeList[j].ID.ToString() == distanceInfo[2])
                            bNode = nodeList[j];
                    }

                    NodeDistance nodeDistance = new NodeDistance(Convert.ToInt32(distanceInfo[0]), aNode, bNode);

                    distanceList.Add(nodeDistance);
                }

                respond = false;
                for (int i = 0; i < nodeList.Count; i++)                 //更新nodeDataGridView
                {
                    nodeDataGridView.Rows.Add();  //增加一行

                    nodeDataGridView[0, i].Value = nodeList[i].ID;
                    nodeDataGridView[1, i].Value = nodeList[i].X;
                    nodeDataGridView[2, i].Value = nodeList[2].Y;
                }
                respond = true;

                for (int i = 0; i < distanceList.Count; i++)              //更新distanceDataGridView
                {
                    distanceDataGridView.Rows.Add();
                    distanceDataGridView[0, i].Value = distanceList[i].ID;
                    distanceDataGridView[1, i].Value = distanceList[i].ANodeID;
                    distanceDataGridView[2, i].Value = distanceList[i].BNodeID;
                    distanceDataGridView[3, i].Value = distanceList[i].Distance;
                }

                streamRead.Close();
                Invalidate();
            }

        }
    }
}
